package com.sinbader.xiaole.appapi.controller;

import cn.stylefeng.guns.sys.core.auth.AuthServiceImpl;
import cn.stylefeng.guns.sys.core.constant.state.ManagerStatus;
import cn.stylefeng.guns.sys.core.util.SaltUtil;
import cn.stylefeng.guns.sys.core.util.UserKit;
import cn.stylefeng.guns.sys.modular.enums.UserTypes;
import cn.stylefeng.guns.sys.modular.system.entity.User;
import cn.stylefeng.guns.sys.modular.system.model.UserDto;
import cn.stylefeng.guns.sys.modular.system.service.UserService;
import cn.stylefeng.roses.kernel.model.response.ResponseData;
import cn.stylefeng.roses.kernel.model.response.SuccessResponseData;
import com.sinbader.xiaole.appapi.service.SmsService;
import com.sinbader.xiaole.appapi.service.WxLoginService;
import com.sinbader.xiaole.common.enums.RedisKeys;
import com.sinbader.xiaole.common.model.params.WxUserInfoParams;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Api(tags = "用户")
@RestController
@RequestMapping("/user")
public class UserController {

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	@Autowired
	private UserService userService;

	@Autowired
	private SmsService smsService;

	@Autowired
	private AuthServiceImpl authService;
	@Autowired
	private WxLoginService wxLoginService;

	@ApiOperation(value = "发送手机登录验证码")
	@GetMapping("sendLoginSmsCode")
	public ResponseData sendLoginPhoneCode(@ApiParam("手机号") @RequestParam(required = true) String phone) {
		String redisKey = RedisKeys.getLoginSmsCode(phone);
		String redisKey1Min = RedisKeys.getLoginSmsCode1Min(phone);
		ResponseData errorResponseData = smsService.checkSendSmsCode(phone, redisKey1Min);
		if(errorResponseData != null) {
			return errorResponseData;
		}
		// redis 如果有手机号对应的验证码，则直接使用，没有则新生成
		String code = smsService.genCode(redisKey);
		// 发送短信，保存记录， 存 redis
		smsService.sendLoginSmsCode(phone, code);
		stringRedisTemplate.opsForValue().set(redisKey1Min, code, 1, TimeUnit.MINUTES);
		stringRedisTemplate.opsForValue().set(redisKey, code, 30, TimeUnit.MINUTES);
		return ResponseData.success();
	}


	@ApiOperation(value = "发送手机号注册验证码")
	@GetMapping("sendRegisterSmsCode")
	public ResponseData sendRegisterSmsCode(@ApiParam("手机号") @RequestParam(required = true) String phone) {
		String redisKey = RedisKeys.getRegistSmsCode(phone);
		String redisKey1Min = RedisKeys.getRegistSmsCode1Min(phone);
		ResponseData errorResponseData = smsService.checkSendSmsCode(phone, redisKey1Min);
		if(errorResponseData != null) {
			return errorResponseData;
		}
		// redis 如果有手机号对应的验证码，则直接使用，没有则新生成
		String code = smsService.genCode(redisKey);
		// 发送短信，保存记录， 存 redis
		smsService.sendRegistSmsCode(phone, code);
		stringRedisTemplate.opsForValue().set(redisKey1Min, code, 1, TimeUnit.MINUTES);
		stringRedisTemplate.opsForValue().set(redisKey, code, 30, TimeUnit.MINUTES);
		return ResponseData.success();
	}

	@ApiOperation(value = "发送密码重置验证码")
	@GetMapping("sendResetPasswordSmsCode")
	public ResponseData sendResetPasswordSmsCode(@ApiParam("手机号") @RequestParam(required = true) String phone) {
		String redisKey = RedisKeys.getResetPasswordSmsCode(phone);
		String redisKey1Min = RedisKeys.getResetPasswordSmsCode1Min(phone);
		ResponseData errorResponseData = smsService.checkSendSmsCode(phone, redisKey1Min);
		if(errorResponseData != null) {
			return errorResponseData;
		}
		// redis 如果有手机号对应的验证码，则直接使用，没有则新生成
		String code = smsService.genCode(redisKey);
		// 发送短信，保存记录， 存 redis
		smsService.sendResetPasswordSmsCode(phone, code);
		stringRedisTemplate.opsForValue().set(redisKey1Min, code, 1, TimeUnit.MINUTES);
		stringRedisTemplate.opsForValue().set(redisKey, code, 30, TimeUnit.MINUTES);
		return ResponseData.success();
	}

	@ApiOperation(value = "发送手机号绑定验证码")
	@GetMapping("sendBindPhoneSmsCode")
	public ResponseData sendBindPhoneSmsCode(@ApiParam("手机号") @RequestParam(required = true) String phone) {
		String redisKey = RedisKeys.getBindPhoneSmsCode(phone);
		String redisKey1Min = RedisKeys.getBindPhoneSmsCode1Min(phone);
		ResponseData errorResponseData = smsService.checkSendSmsCode(phone, redisKey1Min);
		if(errorResponseData != null) {
			return errorResponseData;
		}
		// redis 如果有手机号对应的验证码，则直接使用，没有则新生成
		String code = smsService.genCode(redisKey);
		// 发送短信，保存记录， 存 redis
		smsService.sendBindPhoneSmsCode(phone, code);
		stringRedisTemplate.opsForValue().set(redisKey1Min, code, 1, TimeUnit.MINUTES);
		stringRedisTemplate.opsForValue().set(redisKey, code, 30, TimeUnit.MINUTES);
		return ResponseData.success();
	}


	@ApiOperation(value = "注册（短信验证码）")
	@PostMapping("/registerBySmsCode")
	public ResponseData registerBySmsCode(@ApiParam("手机号") @RequestParam(required = true) String phone,
										@ApiParam("验证码") @RequestParam(required = true) String code,
										@ApiParam("密码") @RequestParam(required = true) String password) {
		phone = StringUtils.trim(phone);
		User user = userService.getByAccount(phone);
		if(user != null) {
			return ResponseData.error("此手机号用户已存在");
		}
		String redisKey = RedisKeys.getRegistSmsCode(phone);
		String redisSmsCode = stringRedisTemplate.opsForValue().get(redisKey);
		if( ! Objects.equals(code, redisSmsCode)) {
			return ResponseData.error("验证码错误");
		}
		UserDto userDto = new UserDto();
		userDto.setAccount(phone);
		userDto.setPassword(password);
		userDto.setType(UserTypes.Common);
		userService.addUser(userDto);
		return ResponseData.success();
	}

	@ApiOperation(value = "登录（密码）")
	@PostMapping("/loginByPassword")
	public ResponseData loginByPassword(@ApiParam("手机号 或 账号") @RequestParam(required = true) String account,
										@ApiParam("密码") @RequestParam(required = true) String password) {

		if(StringUtils.isBlank(account)) {
			return ResponseData.error("用户名为空");
		}
		if(StringUtils.isBlank(password)) {
			return ResponseData.error("密码为空");
		}
		//登录并创建token
		String token = authService.login(account, password);
		return new SuccessResponseData(token);
	}


	@ApiOperation(value = "登录（短信验证码）")
	@PostMapping("/loginBySmsCode")
	public ResponseData loginBySmsCode(@ApiParam("手机号") @RequestParam(required = true) String phone,
									   @ApiParam("短信验证码") @RequestParam(required = true) String smsCode) {
		phone = StringUtils.trimToNull(phone);
		if(StringUtils.isBlank(phone)) {
			return ResponseData.error("手机号为空");
		}
		if(StringUtils.isBlank(smsCode)) {
			return ResponseData.error("验证码为空");
		}

		// 验证码是否正确
		String redisKey = RedisKeys.getLoginSmsCode(phone);
		String redisSmsCode = stringRedisTemplate.opsForValue().get(redisKey);
		if( ! StringUtils.equals(smsCode, redisSmsCode)) {
			return ResponseData.error("验证码错误");
		}

		User user = userService.getByAccount(phone);
		if(user == null) {
			user = new User()
					.setAccount(phone)
					.setType(UserTypes.Common)
					.setCreateTime(new Date())
					.setStatus(ManagerStatus.OK.getCode());
			userService.save(user);
		}
		String token = authService.login(phone);
		return ResponseData.success(token);
	}


	@ApiOperation(value = "重置密码（短信验证码）")
	@PostMapping("resetPasswordBySmsCode")
	public ResponseData resetPasswordBySmsCode(@ApiParam("手机号") @RequestParam(required = true) String phone,
									  @ApiParam("验证码") @RequestParam(required = true) String smsCode,
									  @ApiParam("密码") @RequestParam(required = true) String password) {

		if(StringUtils.length(password) < 6) {
			return ResponseData.error("密码最少 6 位");
		}

		User user = userService.getByAccount(phone);
		if(user == null) {
			return ResponseData.error("用户不存在");
		}

		// 判断 验证码
		String redisKey = RedisKeys.getResetPasswordSmsCode(phone);
		String redisSmsCode = stringRedisTemplate.opsForValue().get(redisKey);
		if( ! StringUtils.equals(smsCode, redisSmsCode)) {
			return ResponseData.error("验证码错误");
		}

		// 重置密码
		String salt = SaltUtil.getRandomSalt();
		String md5Password = SaltUtil.md5Encrypt(password, salt);
		user.setPassword(md5Password);
		user.setSalt(salt);
		userService.updateById(user);

		return ResponseData.success();
	}

	@ApiOperation(value = "绑定手机号（短信验证码）")
	@PostMapping("/bindPhoneBySmsCode")
	public ResponseData bindPhoneBySmsCode(@ApiParam("手机号") @RequestParam(required = true) String phone,
										   @ApiParam("验证码") @RequestParam(required = true) String smsCode) {
		String redisKey = RedisKeys.getBindPhoneSmsCode(phone);
		String redisSmsCode = stringRedisTemplate.opsForValue().get(redisKey);
		if( ! StringUtils.equals(smsCode, redisSmsCode)) {
			return ResponseData.error("验证码错误");
		}

		User user = UserKit.getUser();
		if( ! UserTypes.Common.equals(user.getType())) {
			return ResponseData.error("系统管理员请在后台系统设置");
		}

		User phoneUser = userService.getByAccount(phone);
		if(phoneUser != null && !Objects.equals(user.getUserId(), phoneUser.getUserId())) {
			return ResponseData.error("其它用户已绑定此手机号");
		}

		user.setAccount(phone);
		user.setPhone(phone);
		userService.updateById(user);
		return ResponseData.success();
	}

	@ApiOperation(value = "登录（微信）")
	@PostMapping("/loginByWeinxin")
	public ResponseData loginByWeixin(@RequestBody WxUserInfoParams userInfo) {
		if (userInfo == null || StringUtils.isBlank(userInfo.getUnionId())) {
			return ResponseData.error("参数缺失 unionId");
		}
		String token = wxLoginService.login(userInfo);
		return ResponseData.success(token);
	}

	@ApiOperation(value = "绑定微信")
	@PostMapping("/bindWeixin")
	public ResponseData bindWeixin(@RequestBody WxUserInfoParams userInfo) {
		if (userInfo == null || StringUtils.isBlank(userInfo.getUnionId())) {
			return ResponseData.error("参数缺失 unionId");
		}
		User user = UserKit.getUser();
		if(user == null) {
			return ResponseData.error("未登录");
		}

		User wxUser = userService.getByWxUnionId(userInfo.getUnionId());
		if(wxUser != null && Objects.equals(wxUser.getUserId(), user.getUserId())) {
			return ResponseData.error("此微信已绑定到其它账号");
		}

		// 绑定微信
		user.setWxUnionId(userInfo.getUnionId());
		user.setAvatar(userInfo.getAvatar());
		user.setNickName(userInfo.getNickName());
		userService.updateById(user);
		return ResponseData.success();
	}

}
